//
// Created by WenDaojiang on 15/11/22.
// Copyright (c) 2015 文道江. All rights reserved.
//


#import "URLSessionManager.h"

@implementation URLSessionManager

+ (URLSessionManager *)defaultManager {
    static URLSessionManager *_instance = nil;

    @synchronized (self) {
        if (_instance == nil) {
            _instance = [[self alloc] init];
        }
    }

    return _instance;
}

+ (URLSessionManager *)manager{
    return [[self alloc] init];
}

- (instancetype)init {
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    self = [super initWithSessionConfiguration: configuration];
    if (self) {
        self.responseSerializer = [AFHTTPResponseSerializer serializer];
        self.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
        self.securityPolicy.allowInvalidCertificates = YES;
    }

    return self;
}

+ (NSMutableURLRequest *)createRequestWithURL:(NSURL *)url{
    return [[self defaultManager] createRequestWithURL:url];
}

+ (NSMutableURLRequest *)createRequestWithURLString:(NSString *)url{
    return [self createRequestWithURL:[NSURL URLWithString:url]];
}

+ (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url
                        completionHandler:(void (^)(NSURLResponse *, id, NSError *))completionHandler {

    return [[self defaultManager] dataTaskWithURL:url completionHandler:completionHandler];
}

+ (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
                                             progress:(NSProgress *__autoreleasing *)progress
                                          destination:(NSURL *(^)(NSURL *targetPath, NSURLResponse *response))destination
                                    completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler {

    return [[self defaultManager] downloadTaskWithRequest:request
                                                 progress:progress
                                              destination:destination
                                        completionHandler:completionHandler];
}

+ (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
                                                progress:(NSProgress *__autoreleasing *)progress
                                             destination:(NSURL *(^)(NSURL *targetPath, NSURLResponse *response))destination
                                       completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler {

    return [[self defaultManager] downloadTaskWithResumeData:resumeData
                                                    progress:progress
                                                 destination:destination
                                           completionHandler:completionHandler];
}

+ (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                                                 progress:(NSProgress *__autoreleasing *)progress
                                        completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler {

    return [[self defaultManager] uploadTaskWithStreamedRequest:request
                                                       progress:progress
                                              completionHandler:completionHandler];
}

+ (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromData:(NSData *)bodyData
                                         progress:(NSProgress *__autoreleasing *)progress
                                completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler {

    return [[self defaultManager] uploadTaskWithRequest:request
                                               fromData:bodyData
                                               progress:progress
                                      completionHandler:completionHandler];
}

+ (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromFile:(NSURL *)fileURL
                                         progress:(NSProgress *__autoreleasing *)progress
                                completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler {

    return [[self defaultManager] uploadTaskWithRequest:request
                                               fromFile:fileURL
                                               progress:progress
                                      completionHandler:completionHandler];
}

+ (NSProgress *)uploadProgressForTask:(NSURLSessionUploadTask *)uploadTask {
    return [[self defaultManager] uploadProgressForTask:uploadTask];
}

+ (NSProgress *)downloadProgressForTask:(NSURLSessionDownloadTask *)downloadTask {
    return [[self defaultManager] downloadProgressForTask:downloadTask];
}


- (NSMutableURLRequest *)createRequestWithURL:(NSURL *)url {

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    UIDevice *device = [UIDevice currentDevice];
    NSString *userAgent = [NSString stringWithFormat:@"Mozilla/5.0 (%@; CPU %@ %@ like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/%@ Mobile/11A465 Safari/9537.53", device.model, device.systemName, device.systemVersion, device.systemVersion];
    [UIApplication sharedApplication];
    [request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
    return request;
}

- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url
                        completionHandler:(void (^)(NSURLResponse *, id, NSError *))completionHandler {

    return [self dataTaskWithRequest:[self createRequestWithURL:url] completionHandler:completionHandler];
}

+ (NSURLSessionDataTask *)ajax:(NSString *)method
                           url:(NSURL *)url
                      dataType:(NSString *)dataType
                        params:(NSDictionary *)params
                    completion:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler {
    NSMutableURLRequest *request;

    if ([method.lowercaseString isEqualToString:@"post"] || [method.lowercaseString isEqualToString:@"put"]) {
        request = [self createRequestWithURL:url];
        NSString *mimeType = [URLUtils getMIMEType:dataType];
        [request setValue:[NSString stringWithFormat:@"%@; charset=UTF-8", mimeType] forHTTPHeaderField:@"Content-Type"];
        NSData *body = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil];
        [request setHTTPBody:body];
        [request setHTTPMethod:method.uppercaseString];
    } else {
        NSString *query = params.urlEncodedString;
        if (query && query.length > 0) {
            if (url.query) {
                query = [url.query stringByAppendingFormat:@"&%@", query];
            }
        }
        NSURLComponents *components = [NSURLComponents componentsWithString:url.absoluteString];
        components.query = query;
        request = [self createRequestWithURL:components.URL];
    }

    [request setValue:@"XMLHttpRequest" forHTTPHeaderField:@"X-Requested-With"];
    //[request setValue:@"gzip, deflate" forHTTPHeaderField:@"Content-Encoding"];

    return [[self defaultManager] dataTaskWithRequest:request completionHandler:completionHandler];
}

+ (NSURLSessionDataTask *)ajax:(NSString *)method
                           url:(NSURL *)url
                      dataType:(NSString *)dataType
                        params:(NSDictionary *)params
             completionHandler:(void (^)(NSDictionary *data, NSError *error))completionHandler {

    return [self ajax:method
                  url:url
            dataType:dataType
               params:params
           completion:^(NSURLResponse *response, id responseObject, NSError *error) {
               if (error == nil) {
                   NSError *err;
                   NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableLeaves error:&err];
                   completionHandler(dictionary, err);
               } else {
                   completionHandler(nil, error);
                   NSLog(@"NSURLResponse %@, %@, %@", response, responseObject, error);
               }
           }];
}

+ (NSURLSessionDataTask *)ajax:(NSString *)method
                           url:(NSURL *)url
                        params:(NSDictionary *)params
             completionHandler:(void (^)(NSDictionary *data, NSError *error))completionHandler{
    return [self ajax:method url:url dataType:@"json" params:params completionHandler:completionHandler];
}

+ (NSURLSessionDataTask *)ajaxPOST:(NSString *)url
                            params:(NSDictionary *)params
                 completionHandler:(void(^)(NSDictionary *data, NSError *error))completionHandler{

    return [self ajax:@"POST" url:[NSURL URLWithString:url] params:params completionHandler:completionHandler];
}

+ (NSURLSessionDataTask *)ajaxGET:(NSString *)url
                           params:(NSDictionary *)params
                completionHandler:(void(^)(NSDictionary *data, NSError *error))completionHandler{

    return [self ajax:@"GET" url:[NSURL URLWithString:url] params:params completionHandler:completionHandler];
}

@end

// helper function: get the string form of any object
static NSString *toString(id object) {
    return [NSString stringWithFormat: @"%@", object];
}

// helper function: get the url encoded string form of any object
static NSString *urlEncode(id object) {
    NSString *string = toString(object);
    return [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
}

@implementation NSDictionary (UrlEncoding)

-(NSString*) urlEncodedString {
    NSMutableArray *parts = [NSMutableArray array];
    for (id key in self) {
        id value = self[key];
        NSString *part = [NSString stringWithFormat: @"%@=%@", urlEncode(key), urlEncode(value)];
        [parts addObject: part];
    }
    return [parts componentsJoinedByString: @"&"];
}

@end

@implementation NSString (UrlEncoding)

-(NSString*) urlEncodedString {
    return [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
}

-(NSString*) urlDecodedString {
    return [self stringByRemovingPercentEncoding];
}

@end

@implementation URLUtils

+ (NSString *)fileMIMEType:(NSString *)file {
    return [self getMIMEType:file.pathExtension];
}

+ (NSString *)getMIMEType:(NSString *)ext {
    CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef) ext, NULL);
    CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
    CFRelease(UTI);
    return (__bridge NSString *) MIMEType;
}


@end
